from twisted.plugin import IPlugin
from zope.interface import implements

from pyhsrv.interfaces import IActionPlugin
from pyhsrv import errors

from twisted.internet import protocol, reactor, defer, ssl
from twisted.protocols import basic
from twisted.application import internet

from ConfigParser import SafeConfigParser

class alertProto(basic.NetstringReceiver):
    
    def sendMsg(self, msg):
        self.sendString(msg)

class ForwardingAction(object):
    
    implements(IPlugin, IActionPlugin)

    def __init__(self):
        self.name = "forward"

    def configure(self, cfg, db):
        self.cfg = cfg
        self.db  = db
        self.servername = cfg.get('general', 'servername')
        self.parents = {}
        def fillParents(servers):
            for s in servers:
                if s.proto in [0, 10]:
                    self.parents[s.name] = [s.addr, s.alertport, s.proto >= 10]
        d = db.getParents(self.servername, session = True)
        d.addCallback(fillParents)
        d.addErrback(errors.catchError)

    def getName(self):
        return self.name
        
    def gotproto(self, p):
        p.sendMsg(self.msg)
        p.transport.loseConnection()

    def send(self, addr_and_port):
        c = protocol.ClientCreator(reactor, alertProto)
        if addr_and_port[2]:
            print "SSL"
            # read the configuration:
            myKey = self.cfg.get('general', 'mysslcert')
            trustedCA = self.cfg.get('general', 'casslcert')
            
            # read the certificate files:
            fd = open(myKey,'r')
            theCert = ssl.PrivateCertificate.loadPEM(fd.read())
            fd.close()
            fd = open(trustedCA,'r')
            theCA = ssl.Certificate.loadPEM(fd.read())
            fd.close()
            ctx = theCert.options(theCA)
            
            # set the SSL version to v3:
            ctx.method = ssl.SSL.SSLv3_METHOD
            
            # If True, verify certificates received from the peer and fail
            # the handshake if verification fails. Otherwise, allow anonymous
            # sessions and sessions with certificates which fail validation.
            ctx.verify = True

            # Depth in certificate chain down to which to verify.
            ctx.verifyDepth = 1
       
            # If True, do not allow anonymous sessions.
            ctx.requireCertification = True
       
            # If True, do not re-verify the certificate on session resumption.
            ctx.verifyOnce = True
       
            # If True, generate a new key whenever ephemeral DH parameters are
            # used to prevent small subgroup attacks.
            ctx.enableSingleUseKeys = True
       
            # If True, set a session ID on each context. This allows a shortened
            # handshake to be used when a known client reconnects.
            ctx.enableSessions = True
       
            # If True, enable various non-spec protocol fixes for broken
            # SSL implementations.
            ctx.fixBrokenPeers = False
            d = c.connectSSL(addr_and_port[0], addr_and_port[1], ctx)
        else:
            d = c.connectTCP(addr_and_port[0], addr_and_port[1])
        d.addCallback(self.gotproto)
        

    def doAction(self, tmstmp, node, itm, value, type, group, msg):
        self.msg = self.servername + " " + node + " " + type + " " + itm + \
            " " + value
        for i in self.parents.keys():
            self.send(self.parents[i])

fa = ForwardingAction()
